package inge_soft.gestoriusNuevo.business.service.implementation;

import inge_soft.gestoriusNuevo.business.logic.abstraction.IManejadorMail;
import inge_soft.gestoriusNuevo.business.logic.abstraction.IRandomStringGeneration;
import inge_soft.gestoriusNuevo.business.service.abstraction.IUsuarioService;
import inge_soft.gestoriusNuevo.persistence.DAO.Exceptions.Abstraction.GestoriusException;
import inge_soft.gestoriusNuevo.persistence.DAO.Exceptions.Implementation.ErrorMergeUsuario;
import inge_soft.gestoriusNuevo.persistence.DAO.Exceptions.Implementation.UsuarioInexistenteException;
import inge_soft.gestoriusNuevo.persistence.DAO.abstraction.IDocumentoDAO;
import inge_soft.gestoriusNuevo.persistence.DAO.abstraction.IDomicilioDAO;
import inge_soft.gestoriusNuevo.persistence.DAO.abstraction.ILocalidadDAO;
import inge_soft.gestoriusNuevo.persistence.DAO.abstraction.IPaisDAO;
import inge_soft.gestoriusNuevo.persistence.DAO.abstraction.ITipoDocumentoDAO;
import inge_soft.gestoriusNuevo.persistence.DAO.abstraction.IUsuarioDAO;
import inge_soft.gestoriusNuevo.persistence.DAO.abstraction.IUsuarioRegistradoDAO;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Documento;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Domicilio;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Localidad;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Pais;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.TipoDocumento;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.Usuario;
import inge_soft.gestoriusNuevo.persistence.entity.implementation.UsuarioRegistrado;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("usuarioService")
public class UsuarioService implements IUsuarioService {

	@Autowired
	@Qualifier("usuarioDAO")
	IUsuarioDAO usuarioDAO;
	
	@Autowired
	@Qualifier("usuarioRegistradoDAO")
	IUsuarioRegistradoDAO usuarioRegistradoDAO;
	
	@Autowired
	@Qualifier("documentoDAO")
	IDocumentoDAO documentoDAO;
	
	@Autowired
	@Qualifier("domicilioDAO")
	IDomicilioDAO domicilioDAO;
	
	@Autowired
	@Qualifier("manejadorMail")
	IManejadorMail manejadorMail;
	
	@Autowired
	@Qualifier("tipoDocumentoDAO")
	ITipoDocumentoDAO tipoDocumentoDao;
	
	@Autowired
	@Qualifier("paisDAO")
	IPaisDAO paisDAO;
	
	@Autowired
	@Qualifier("localidadDAO")
	ILocalidadDAO localidadDAO;

	@Autowired
	@Qualifier("generadorPassRandom")
	IRandomStringGeneration generadorPassRandom;
	
	// MEDIANTE EL DAO DE USUARIO
	
	@Transactional(readOnly = true)
	public Usuario obtenerUsuario(long id){
		return usuarioDAO.findById(id);
	}
	
	/*@Transactional	ESTARIA MAL, PATEA LOGICA PARA EL CONTROLLER
	public void crearUsuario(Usuario usuario) throws DataAccessException {
		usuarioDAO.save(usuario);
	}*/
	
	@Transactional
	public void crearUsuario(Usuario usuario, UsuarioRegistrado usuarioRegistrado, Documento documento, Domicilio domicilio)
			throws DataAccessException {
		
		// primero habria que preguntar si existen los objetos con atributos unique!!!!
		
		if (domicilio != null) {
			domicilioDAO.crear(domicilio); // si ingreso domicilio, lo persisto
		}
		
		documentoDAO.crear(documento); // persisto documento
		usuario.setDomicilio(domicilio);
		usuario.setDocumento(documento);

		usuarioDAO.save(usuario);	// persiste el usuario
		usuarioRegistrado.setUsuario(usuario);	// al usuario registrado le seteo el usuario
		usuarioRegistradoDAO.crearUsuario(usuarioRegistrado);	// persisto el usuario registrado

		
		/* si llego hasta ACA, es porque no lanzaron excepcion los DAOs */
		String mensajeBienvenida = "¡Bienvenido a Gestorius!\n\n" +
				"Su nombre de usuario es: " + usuarioRegistrado.getNick() + "\n" +
				"Su contraseña es: " + usuarioRegistrado.getContrasenia();
		String asunto = "Bienvenido a Gestorius";

		manejadorMail.mandarMail(mensajeBienvenida, asunto, usuario.getMail());
	}

	@Transactional
	public void modificarUsuario(Usuario usuario) throws DataAccessException {
		usuarioDAO.update(usuario);
	}

	@Transactional
	public void eliminarUsuario(Usuario usuario) throws DataAccessException {
		usuarioDAO.delete(usuario);
	}

	@Transactional(readOnly = true)
	public List<Usuario> buscarTodosUsuarios() throws DataAccessException {
		return usuarioDAO.listAll();
	}

	public List<TipoDocumento> obtenerTodosTiposDocumentoOrdenadosPorNombreAscendente() throws GestoriusException {
		return tipoDocumentoDao.obtenerTodosOrdenadosPorNombreAscendente();
	}

	public List<Pais> obtenerTodosLosPaisesOrdenadosPorNombreNacionalidadAscendente() throws GestoriusException {
		return paisDAO.obtenerTodosLosPaisesOrdenadosPorNombreNacionalidadAscendente();
	}

	/**
	 * Si el pais que me pasan es nulo, devuelvo una lista vacia,
	 * Cuando el pais NO es nulo, hago la consulta
	 */
	public List<Localidad> obtenerTodasLasLocalidadesDePaisOrdenadasPorNombreAscendente(Pais pais) throws GestoriusException {
		if (pais == null) {
			return new ArrayList<Localidad>();
		}
		return localidadDAO.obtenerTodasLasLocalidadesDePaisOrdenadasPorNombreAscendente(pais);
	}

	public List<Localidad> obtenerTodasLasLocalidadesDePaisQueCoincidaConCodigoPostalOrdenadasPorNombreAscendente(
			Pais pais, String codigoPostal) {
		return localidadDAO.obtenerTodasLasLocalidadesDePaisQueCoincidaConCodigoPostalOrdenadasPorNombreAscendente(
				pais, codigoPostal);
		
	}

	public List<Pais> obtenerTodosLosPaisesOrdenadosPorNombreAscendente() throws GestoriusException {
		return paisDAO.obtenerTodosLosPaisesOrdenadosPorNombreAscendente();
	}

	public List<Localidad> obtenerLasLocalidadesDePaisQueCoincidanConNombreOrdenadasPorNombreAscendente(
			Pais pais, String nombre) throws GestoriusException {
		
		return localidadDAO.obtenerLasLocalidadesDePaisQueCoincidanConNombreOrdenadasPorNombreAscendente(pais, nombre);
	}
	
	
	
	
	// MEDIANTE EL DAO DE USUARIOREGISTRADO
	
	
	
	@Transactional(readOnly = true)
	public UsuarioRegistrado obtenerUsuarioRegistrado(String nick) {
		try{
		return usuarioRegistradoDAO.findByNick(nick);
		}
		catch(UsuarioInexistenteException e1){
			throw e1;
		}
	}

	
	@Transactional
	public void crearUsuarioRegistrado(UsuarioRegistrado usuarioR)
			throws GestoriusException {
		usuarioRegistradoDAO.crearUsuario(usuarioR);
		
	}

	
	@Transactional
	public void modificarUsuarioRegistrado(UsuarioRegistrado usuarioR)
			throws GestoriusException {
		try{
		usuarioRegistradoDAO.modificarUsuario(usuarioR);
		}
		catch(ErrorMergeUsuario e1){
			throw e1;
		}
	}
	
	
	@Transactional
	public void eliminarUsuarioRegistrado(UsuarioRegistrado usuarioR)
			throws GestoriusException {
		usuarioRegistradoDAO.eliminarUsuario(usuarioR);
		
	}
	
	@Transactional(readOnly = true)
	public UsuarioRegistrado obtenerUsuarioRegistrado(Long idUsuario) throws UsuarioInexistenteException {
		
		Usuario user;
		try{
			user = usuarioDAO.findById(idUsuario);
		} catch(GestoriusException e){
			throw new UsuarioInexistenteException("Usuario inexistente");
		}
		
		
		try {
			return usuarioRegistradoDAO.findByUsuario(user);
		} catch (UsuarioInexistenteException e1) {
			throw e1;
		}
	}

	
	@Transactional(readOnly = true)
	public List<UsuarioRegistrado> buscarTodosUsuarioRegistrado(
			UsuarioRegistrado usuarioR) throws GestoriusException {
		usuarioRegistradoDAO.listAllOrderByName();
		return null;
	}
	

	@Transactional(readOnly = true)
	public UsuarioRegistrado verificarLogin(UsuarioRegistrado usr)
			throws GestoriusException {
		try{
		 return usuarioRegistradoDAO.verificarLogin(usr);
		}
		catch(GestoriusException e1){
			//System.out.println("rethrow service");
			throw e1;
		}
		
	}

	public void enviarMailReestablecerContrasenia(UsuarioRegistrado usr) {
		String mensaje="Su contrase�a ha sido reestablecida./n Su nueva contrase�a es "+ usr.getContrasenia();
		String asunto = "Gestorius - Reestablecer contrase�a";
		System.out.println("usuario: "+usr.getUsuario());
		
		this.manejadorMail.mandarMail(mensaje, asunto, usr.getUsuario().getMail());
		
	}

	public String generadorStringRandom() {
		return this.generadorPassRandom.getRandomString();
	}
	

	

}